#include "tjm_action.hpp"
#include "fighting.hpp"
#include "lines.hpp"
#include "mockif.hpp"
#include "params.hpp"
#include "udp.h"
#include <ctime>

extern price_t g_hop;
extern UdpClient* g_uc;
extern int debug_level;

void
do_something()
{
}

namespace Trade {

int
TJM::send_pet_timer(const dir_t d,
                    const int8_t type,
                    const time_t t1,
                    const time_t t2,
                    const time_t tm,
                    const price_t hpx,
                    const int8_t renew) const noexcept
{
  if (debug_level) {
    static const char* format = "{\"i\":%ld,\"t\":%d,\"p\":%.02lf,\"d\":%d,"
                                "\"t1\":%ld,\"t2\":%ld,\"r\":%d}";

    char buf[512];
    snprintf(buf, 512, format, tm, hpx, type, d, t1, t2, renew);

    return udpc_send_message(g_uc, buf);
  }

  return (0);
}

int
TJM::reached(event_t& event, Lines& lines) noexcept
{
  // lines.limit_reached(hp_now_);

  r_tom = 0;
  r_jerry = 0;
  r_mickey = 0;
  r_swing = 0;

  int ret = 0;

  if (tom.is_running()) {
    tom.incomming.update_revenue(
      hp_now_, tom.get_dir(), tom.os_entries, 1, t_now_, idx__);

    bool big_reverse_changed =
      tom.incomming.big_needle_changed(hp_now_, t_now_);
    if (big_reverse_changed) {
      if (tom.incomming.d_big_reverse) {
        tm_big_needle = tom.incomming.tm_rvn_max;
        event |= EVENT_BIG_NEEDLE_OCCURED;
        // printf("!!! <<< Big Needle %d Warning >>> %ld %ld!!!\n",
        //        tom.incomming.d_big_reverse,
        //        t_now_,
        //        idx__);
      } else {
        tm_big_needle = 0;
        event |= EVENT_BIG_NEEDLE_DISAPPEARED;
        // printf("<<< Big Needle Canceled >>> %ld %ld\n", t_now_, idx__);
      }
    }

    bool big_reverse = tom.incomming.big_reverse_changed(hp_now_, t_now_);
    if (big_reverse) {
      if (tom.incomming.im_big_reverse) {
        // printf("!!! <<< Big Reverse Warning >>> %.02lf %ld %ld\n",
        //        tom.incomming.rvn_single - tom.incomming.rvn_max,
        //        t_now_,
        //        idx__);
        tm_big_reverse = tom.incomming.tm_rvn_max;
        event |= EVENT_BIG_REVERSE_OCCURED;
      } else {
        tm_big_reverse = 0;
        event |= EVENT_BIG_REVERSE_DISAPPEARED;
        // printf("<<< Big Reverse Canceled >>> %ld %ld\n", t_now_, idx__);
      }
    }

    r_tom = tom.reached(t_now_, hp_now_, lines, idx__);
    if (r_tom) {
      if (r_tom & LIMIT_REACHED::REACHED_TIMER_OUT) {
        time_t tm = vo->get_strong_timer___(tom.get_dir());
        auto tm2 = vo->get_weak_timer___(tom.get_dir());
        tom.update_timer(tm, tm2);
        send_pet_timer(tom.get_dir(), 11, tm, tm2, tom.my_tm, tom.my_hp, 1);
      }

      // printf(
      //   "TO %d: (S%d, T%d) ", tom.amout_to, vo->dir_turns_space,
      //   tom.get_dir());
      // print_reached("Tom", tom.get_dir(), r_tom, idx__);
      // print_reached("Total Reached", tom.get_dir(), tom.reacheded(),
      // idx__);

      event |= EVENT_TOM_REACHED;
    }
  }

  if (jerry.get_dir()) {
    jerry.incomming.update_revenue(
      hp_now_, jerry.get_dir(), jerry.os_entries, 1, t_now_, idx__);

    r_jerry = jerry.reached(t_now_, hp_now_, lines, idx__);
    if (r_jerry) {
      // printf("TO %d: ", jerry.amout_to);
      // print_reached("Jerry", jerry.get_dir(), r_jerry, idx__);
      // print_reached("Total Reached", jerry.get_dir(), jerry.reacheded(),
      // idx__);
      event |= EVENT_JERRY_REACHED;

      if (r_jerry & LIMIT_REACHED::REACHED_TIMER_OUT) {
        jerry_to_amount++;
        auto t2 = vo->get_weak_timer___(mickey.get_dir());
        auto t1 = vo->get_strong_timer___(mickey.get_dir());
        jerry.update_timer(t1, t2);
        send_pet_timer(
          jerry.get_dir(), 12, t1, t2, jerry.my_tm, jerry.my_hp, 1);
      }
      if (jerry.reached_line2() && jerry_reached < 2) {
        jerry_reached = 2;
      } else if (jerry.reached_line1() && jerry_reached < 1) {
        jerry_reached = 1;
      }
    }
  }

  if (mickey.get_dir()) {
    dir_t br = mickey.incomming.big_needle_changed(hp_now_, t_now_);
    if (br && br == -mickey.get_dir()) {
      event |= EVENT_BIG_NEEDLE_OCCURED;
    }

    r_mickey = mickey.reached(t_now_, hp_now_, lines, idx__);
    if (r_mickey) {
      // if (r_mickey & LIMIT_REACHED::TIMER_OUT) {
      //   tjm_add_action_mickey_stop(10000);
      // } else {
      //   mickey.erase_opposite_reached(r_mickey);
      // }

      // printf("TO %d: ", mickey.amout_to);
      // print_reached("Mickey", mickey.get_dir(), r_mickey, idx__);
      // print_reached(
      //   "Total Reached", mickey.get_dir(), mickey.reacheded(), idx__);
      if (mickey.reached_line1() || mickey.timer_outed()) {
        event |= EVENT_MICKEY_REACHED;
      }
      if (r_mickey & LIMIT_REACHED::REACHED_TIMER_OUT) {
        t_mickey_t1 = mickey.target.timer.t;
        t_mickey_t2 = mickey.target.timer.t;

        time_t t1 = vo->get_strong_timer___(mickey.get_dir());
        time_t t2 = vo->get_weak_timer___(mickey.get_dir());
        mickey.update_timer(t1, t2);
        send_pet_timer(
          mickey.get_dir(), 13, t1, t2, mickey.my_tm, mickey.my_hp, 1);
      }
    }

    mickey.incomming.update_revenue(
      hp_now_, mickey.get_dir(), mickey.os_entries, 1, t_now_, idx__);
  }

  if (swing.swing) {
    r_swing = swing.reached(t_now_, hp_now_, lines, idx__);
    if (r_swing) {
      if (swing.set_swing_dir(r_swing)) {
        event |= EVENT_SWING_DIR_CHANGED;
      }
      if (r_swing & LIMIT_REACHED::REACHED_TIMER_OUT) {
        swing.reset();
      } else {
        // if (swing.dir_swing)
        //   swing.target.erase_opposite_reached(-swing.dir_swing, r_swing);
      }
    }
  }

  return ret;
}

void
TJM::print() const noexcept
{
  jerry.print("Jerry", idx__, hp_now_, t_now_);
  mickey.print("Mickey", idx__, hp_now_, t_now_);
  tom.print("Tom", idx__, hp_now_, t_now_);
  swing.print(t_now_, hp_now_);
}

void
TJM::send_timer() const noexcept
{
  if (tom.is_running()) {
    send_pet_timer(tom.get_dir(),
                   11,
                   tom.target.timer.t,
                   tom.target.timer_2.t,
                   tom.my_tm,
                   tom.my_hp,
                   0);
  } else {
    send_pet_timer(0, 11);
  }
  if (jerry.is_running()) {
    send_pet_timer(jerry.get_dir(),
                   12,
                   jerry.target.timer.t,
                   jerry.target.timer_2.t,
                   jerry.my_tm,
                   jerry.my_hp,
                   0);
  } else {
    send_pet_timer(0, 12);
  }
  if (mickey.is_running()) {
    send_pet_timer(mickey.get_dir(),
                   13,
                   mickey.target.timer.t,
                   mickey.target.timer_2.t,
                   mickey.my_tm,
                   mickey.my_hp,
                   0);
  } else {
    send_pet_timer(0, 13);
  }
}

int
TJM::action_jerry_run(const dir_t d, const Lines& l, const case_t cno) noexcept
{
  int ret = 0;
  if (jerry.get_dir() != d) {
    printf("_______________________Jerry run__________________________\n");
    time_t tm1 = vo->get_strong_timer___(d);
    time_t tm2 = vo->get_weak_timer___(d);
    jerry.run(d, tm1, tm2, l, hp_now_, t_now_, idx__, cno, 2);
    send_pet_timer(d, 12, tm1, tm2, jerry.my_tm, jerry.my_hp, 0);
    printf("~~~~~~~~~~~~~~~~~~~~~~~Jerry run~~~~~~~~~~~~~~~~~~~~~~~~~~\n");

    ret = PET_ACTION::JERRY_RUN;
  } else {
  }

  return ret;
}

int
TJM::action_jerry_stop(const case_t cno) noexcept
{
  int ret = 0;
  if (jerry.get_dir()) {
    jerry.stop(idx__, t_now_, cno);
    send_pet_timer(0, 12);
    ret |= PET_ACTION::JERRY_STOP;
  }
  // renew_cat_timer();
  return ret;
}

//
// if hpx > 0, then open with hpx
//        = 0, open with hp_now
//        < 0, do not open close order
//
int
TJM::action_tom_run(const dir_t d,
                    const price_t hpx,
                    const Lines& l,
                    const case_t cno) noexcept
{
  if (!d) {
    return 0;
  }

  if (mickey.is_running()) {
    action_mickey_stop(cno);
  }

  int ret = 0;

  if (d == tom.get_dir()) {
    // CHOOSE should I set the stop price ???D
    printf("<<< Signal >>> Run Tom to %d, \n", d);
  } else {
    ret |= action_tom_stop(hpx, cno);
    ret |= action_jerry_stop(cno);

    time_t tm1 = vo->get_strong_timer___(d);
    time_t tm2 = vo->get_weak_timer___(d);

    tom.run(d, tm1, tm2, l, hp_now_, t_now_, idx__, cno, 1);

    tom.case_no = cno;
    send_pet_timer(d, 11, tm1, tm2, tom.my_tm, tom.my_hp, 0);
    ret |= PET_ACTION::TOM_RUN;
  }

  return ret;
}

//
// if hpx > 0, then close with hpx
//        = 0, close with hp_now
//        < 0, do not place close order
//
int
TJM::action_tom_stop(const price_t hpx, const case_t cno) noexcept
{
  if (tom.get_dir()) {
    if (jerry.is_running() && jerry.get_dir() == tom.get_dir()) {
      action_jerry_stop(cno);
    }

    revenue += tom.incomming.rvn_total;
    ++deal_times;

    auto td = std::make_shared<TheDeal>();
    td->dir = (tom.get_dir() > 0) ? 'l' : 's';
    td->to_amount = tom.amout_to;
    td->reached = tom.target.reached;
    td->c_case = cno;
    td->index = deal_times;
    td->o_idx = tom.my_idx;
    td->o_tm = tom.my_tm;
    td->o_hp = tom.os_entries;
    td->c_idx = idx__;
    td->c_tm = t_now_;
    td->c_hp = hp_now_;
    td->hpx_avg = tom.os_entries;
    td->rvn_px = tom.incomming.rvn_total * g_hop;
    td->rvn_hp = tom.incomming.rvn_single;
    td->rvn_max = tom.incomming.rvn_max;
    td->idx_rvn_max = tom.incomming.idx_rvn_max;
    td->hp_rvn_max = tom.incomming.hp_rvn_max;
    td->rvn_min = tom.incomming.rvn_min;
    td->idx_rvn_min = tom.incomming.idx_rvn_min;
    td->hp_rvn_min = tom.incomming.hp_rvn_min;
    tdv_tom.push_back(td);

    printf(
      "--- \033[38;5;200mCat %d Revenue %.02lf$ (%.02lf) All Revenue %.02lf$ "
      "(%.02lf) Times %u\033[0m ---\n",
      tom.get_dir(),
      tom.incomming.rvn_total * g_hop,
      tom.incomming.rvn_total,
      revenue * g_hop,
      revenue,
      deal_times);

    tom.stop(idx__, t_now_, cno);
    // tom.mock->mock_close_all_position(hp_now_, t_now_, idx__);
    send_pet_timer(0, 11);

    jerry_to_amount = 0;
    jerry_reached = 0;

    return PET_ACTION::TOM_STOP;
  }
  return (0);
}

bool
TJM::vision_dir_opposite_to_tom() const noexcept
{
  return (vo->dir_explicit == -tom.get_dir() ||
          (!vo->dir_explicit && vo->dd3_exp.get_first_dir() == -tom.get_dir()));
}

bool
TJM::vision_dir_sameside_to_tom() const noexcept
{
  return (vo->dir_explicit == tom.get_dir() ||
          (!vo->dir_explicit && vo->dd3_exp.get_first_dir() == tom.get_dir()));
}

static int
get_min_2_time_(const time_t t1,
                const time_t t2,
                const time_t t3,
                const time_t t4,
                const time_t t_now,
                time_t& tm1,
                time_t& tm2) noexcept
{
  int amount = 0;
  time_t t[4];
  int a = 0;
  if (t1 - t_now > 0)
    t[a++] = t1;
  if (t2 - t_now > 0)
    t[a++] = t2;
  if (t3 - t_now > 0)
    t[a++] = t3;
  if (t4 - t_now > 0)
    t[a++] = t4;
  if (a == 0) {
    tm1 = 0;
  } else if (a == 1) {
    tm1 = tm2 = t[0];
    amount = 1;
  } else if (a == 2) {
    tm1 = std::min(t[0], t[1]);
    tm2 = std::max(t[0], t[1]);
    amount = 2;
  } else if (a == 3) {
    tm1 = std::min(t[0], t[1]);
    tm1 = std::min(tm1, t[2]);

    a = 0;
    if (t[0] > tm1)
      t[a++] = t[0];
    if (t[1] > tm1)
      t[a++] = t[1];
    if (t[2] > tm1)
      t[a++] = t[2];
    if (a == 0)
      tm2 = tm1;
    else if (a == 1)
      tm2 = t[0];
    else if (a == 2)
      tm2 = std::min(t[0], t[1]);
    amount = 2;
  } else if (a == 4) {
    tm1 = std::min(t[0], t[1]);
    tm1 = std::min(tm1, t[2]);
    tm1 = std::min(tm1, t[3]);

    a = 0;
    if (t[0] > tm1)
      t[a++] = t[0];
    if (t[1] > tm1)
      t[a++] = t[1];
    if (t[2] > tm1)
      t[a++] = t[2];
    if (t[3] > tm1)
      t[a++] = t[3];
    if (a == 0)
      tm2 = tm1;
    else if (a == 1)
      tm2 = t[0];
    else if (a == 2)
      tm2 = std::min(t[0], t[1]);
    else if (a == 3) {
      tm2 = std::min(t[0], t[1]);
      tm2 = std::min(tm2, t[2]);
    }
    amount = 2;
  }
  return amount;
}

void
TJM::retrive_mickey_timer(const dir_t d,
                          time_t& tm1,
                          time_t& tm2) const noexcept
{
  tm1 = tm2 = 0;
  time_t t1 = vo->get_abs_strong_timer(d);
  time_t t2 = vo->get_abs_weak_timer(d);
  time_t t3 = vo->strong_timer(d);
  time_t t4 = vo->weak_timer(d);
  auto a = get_min_2_time_(t1, t2, t3, t4, t_now_, tm1, tm2);
  if (!a) {
    tm1 = tm2 = t_now_ + MINUTES_45;
  }
}

int
TJM::action_mickey_run(const dir_t d,
                       const price_t hpx,
                       const Lines& l,
                       const case_t cno) noexcept
{
  if (mickey.get_dir() != d) {
    action_mickey_stop(cno);

    printf("_______________________Mickey run__________________________\n");
    time_t tm1 = vo->get_strong_timer___(d);
    time_t tm2 = vo->get_weak_timer___(d);
    mickey.run(d, tm1, tm2, l, hp_now_, t_now_, idx__, cno, 3);

    send_pet_timer(d, 13, tm1, tm2, mickey.my_tm, mickey.my_hp, 0);
    printf("~~~~~~~~~~~~~~~~~~~~~~~Mickey run~~~~~~~~~~~~~~~~~~~~~~~~~~\n");

    return PET_ACTION::MICKEY_RUN;
  }

  return (0);
}

int
TJM::action_mickey_stop(const case_t cno) noexcept
{
  int ret = 0;
  if (mickey.get_dir()) {
    auto td = std::make_shared<TheDeal>();
    td->dir = (mickey.get_dir() > 0) ? 'l' : 's';
    td->to_amount = mickey.amout_to;
    td->reached = mickey.target.reached;
    td->c_case = cno;
    td->o_idx = mickey.my_idx;
    td->o_tm = mickey.my_tm;
    td->o_hp = mickey.os_entries;
    td->c_idx = idx__;
    td->c_tm = t_now_;
    td->c_hp = hp_now_;
    td->hpx_avg = mickey.os_entries;
    td->rvn_px = mickey.incomming.rvn_total * g_hop;
    td->rvn_hp = mickey.incomming.rvn_single;
    td->rvn_max = mickey.incomming.rvn_max;
    td->idx_rvn_max = mickey.incomming.idx_rvn_max;
    td->hp_rvn_max = mickey.incomming.hp_rvn_max;
    td->rvn_min = mickey.incomming.rvn_min;
    td->idx_rvn_min = mickey.incomming.idx_rvn_min;
    td->hp_rvn_min = mickey.incomming.hp_rvn_min;
    tdv_mik.push_back(td);

    mickey.stop(idx__, t_now_, cno);
    ret = PET_ACTION::MICKEY_STOP;
    send_pet_timer(0, 13);
  }
  return ret;
}

void
TJM::print_revenue() noexcept
{
  printf("ALL REVENUE %.02lf $ (%.02lf hop)\n", revenue * g_hop, revenue);
}

void
TJM::reset() noexcept
{
  action_mickey_stop(0);
  action_jerry_stop(0);
  action_tom_stop(0, 0);

  r_tom = 0;
  r_jerry = 0;
  r_mickey = 0;
  r_swing = 0;
  reached_l2_fo = false;
  jerry_reached = 0;
  total_unit = 8;
  vol_per_unit = 16;
  time_reverse_case = 0;

  deal_times = 0;
  jerry_to_amount = 0;
  ft_up = 0;
  ft_dn = 0;
  tjm_cno = 0;

  hp_now_ = 0;
  revenue = 0;
  t_now_ = 0;
  idx__ = 0;
  tm_big_needle = 0;
  tm_big_reverse = 0;

  vo = nullptr;

  tdv_tom.clear();
  tdv_mik.clear();

  tom.incomming.reset();
  tom.reset();
  jerry.incomming.reset();
  jerry.reset();
  mickey.incomming.reset();
  mickey.reset();
  swing.reset();
}

bool
TJM::should_reache_line2(const dir_t d) noexcept
{
  return false;
}

bool
TJM::good_entry_price(const dir_t d, price_t& hp_base, case_t& case_no) noexcept
{
  bool yes = false;

  // Mothed 1. get the delta of dir_explicit

  if (vo->dd3_exp.get_first_dir() && vo->dd3_exp.get_second_dir() &&
      d == vo->dd3_exp.get_first_dir() && -d == vo->dd3_exp.get_second_dir()) {
    price_t delta = vo->dd3_exp.get_first_hp() - vo->dd3_exp.get_second_hp();
    if (sign(delta) == d) {
      hp_base = hp_now_ - delta;
      case_no = 1;
      yes = true;
    }
  }

  return yes;
}

price_t
TJM::finish() noexcept
{
  if (tom.is_running()) {
    action_tom_stop(0, 0);
    mockif.mock_close_all_position(hp_now_, hp_now_, t_now_, idx__);
    int v[4];
    mockif.mock_deal(idx__, hp_now_, vo->t_now_, v);
  }

  if (jerry.is_running()) {
    action_jerry_stop(0);
  }

  if (mickey.is_running()) {
    action_mickey_stop(0);
  }

  printf("ALL REVENUE %.02lf $ (%.02lf hop)\n", revenue * g_hop, revenue);

  mockif.mock_show_deal_record();

  return revenue;
}

int
TJM::lines_changed_() noexcept
{
  int updated = 0;
  if (tom.get_dir()) {
    if (tom.update_lines(vo->lines, hp_now_)) {
      //
      // TODO Update Entry Price
      // TODO Update Close Price
      //
      updated |= 1;
    }
  }

  if (jerry.get_dir() && jerry.update_lines(vo->lines, hp_now_)) {
    updated |= 2;
  }

  if (swing.swing) {
    if (swing.update_lines(vo->lines, hp_now_)) {
      //
      // TODO Update Entry Price
      // TODO Update Close Price
      //
      updated |= 8;
    }
  }

  return updated;
}

bool
TJM::pricing_close_min_to_win(price_t& revenue) const noexcept
{
  //
  // TODO calculate the price
  //
  if (tom.incomming.max_win_rvn > CLOSE_REVENUE_MIN_TO_WIN) {
    revenue = CLOSE_REVENUE_MIN_TO_WIN;

    return true;
  }
  return false;
}

bool
TJM::pricing_close_stop_loss(price_t& revenue) const noexcept
{
  //
  // TODO calculate the price
  //
  revenue = CLOSE_REVENUE_FOOL_FORCED;
  return true;
}

price_t
TJM::priceing_close_good_to_win() const noexcept
{
  return tom.incomming.get_good_for_win(tom.get_dir());
}

bool
TJM::reached_jerry_time_out() const noexcept
{
  return (jerry.is_running() && (r_jerry & LIMIT_REACHED::REACHED_TIMER_OUT));
}

int
TJM::jerry_reached_line2(const event_t event) noexcept
{
  int ret = 0;
  if (event & EVENT_JERRY_REACHED) {
    if ((r_jerry & LIMIT_REACHED::REACHED_DN_2 && tom.get_dir() < 0) ||
        (r_jerry & LIMIT_REACHED::REACHED_UP_2 && tom.get_dir() > 0)) {
      ret = 1;
    }
  }
  return ret;
}

// bool
// TJM::reached_line2_and_force_opposite() noexcept
// {
//   bool yes = false;
//   if (jerry.reached_line2() && jerry.amout_to && tom.reached_line2() &&
//       (vo->dir_force == -tom.get_dir() ||
//        vo->dd3_force.get_first_dir() == -tom.get_dir())) {
//     yes = true;
//   }
//
//   if (reached_l2_fo != yes) {
//     reached_l2_fo = yes;
//     if (yes)
//       return true;
//   }
//
//   return false;
// }

int
TJM::print_all_deal(FILE* fp) noexcept
{
  int ret = 0;
  for (const auto& deal : tdv_tom) {
    // fprintf(fp,
    //         "%d, %c, %d, %.02lf, %ld , %ld, %.02lf, %ld , %ld, %.02lf,
    //         %.02lf, "
    //         "%.02lf, %ld, "
    //         "%.02lf, %.02lf, %ld, %.02lf, %.02lf, %.02lf\n",
    //         deal->index,
    //         deal->dir,
    //         deal->hited,
    //         deal->hpx_avg,
    //         deal->o_idx,
    //         deal->o_tm,
    //         deal->o_hp,
    //         deal->c_idx,
    //         deal->c_tm,
    //         deal->c_hp,
    //         deal->rvn_max,
    //         deal->hp_rvn_max,
    //         deal->idx_rvn_max,
    //         deal->rvn_min,
    //         deal->hp_rvn_min,
    //         deal->idx_rvn_min,
    //         deal->rvn_px,
    //         deal->rvn_hp,
    //         (deal->max_loss_px - deal->o_hp));
    auto n =
      fprintf(fp,
              "%d, %c, %.02lf, %.02lf, %ld , %ld , %.02lf, %ld , %.02lf, "
              "%ld , %.02lf, %.02lf\n",
              deal->index,
              deal->dir,
              deal->hpx_avg,
              deal->o_hp,
              deal->o_idx,
              deal->c_idx,
              deal->rvn_max,
              deal->idx_rvn_max,
              deal->rvn_min,
              deal->idx_rvn_min,
              deal->rvn_px,
              deal->rvn_hp);
    if (n < 0) {
      ret = errno;
      break;
    }
  }
  auto n = fprintf(fp, "\n");
  if (n < 0)
    ret = errno;

  return ret;
}

event_t
TJM::fix_dir_tjm() noexcept
{
  return (0);
}

int
TJM::td_show_revunue() const noexcept
{
  printf("\n\033[38;5;46mRVN\033[0m\n");
  mockif.revenue.print(idx__);
  mockif.pos_up.print(hp_now_, idx__);
  mockif.pos_dn.print(hp_now_, idx__);
  mockif.mock_print_orders_();
  printf("_____________________RVN : g%ld\n\n", idx__);

  return (0);
}

void
TJM::set_whole_position(const int vol) noexcept
{
  whole_position = vol;
}

int
TJM::get_part_volume(const TJM_PART_OF_A_WHOLE part) const noexcept
{
  auto vol = (whole_position / (int)(part));
  return vol;
}

const Lines*
TJM::get_lines(const dir_t d) noexcept
{
  const Lines* pet_lines =
    mickey.is_running()
      ? &mickey.get_limits_lines()
      : (tom.is_running() ? &tom.get_limits_lines() : nullptr);
  if (!pet_lines)
    return &vo->lines;

  const Lines* ptr = &vo->lines;
  if (d > 0) {
    // check 2 up lines
    if (pet_lines->nup == 2 && vo->lines.nup == 1 &&
        pet_lines->hp_up_2 > vo->lines.hp_up_1)
      ptr = pet_lines;
    else if (pet_lines->nup == 2 && vo->lines.nup == 2 &&
             pet_lines->hp_up_2 > vo->lines.hp_up_2)
      ptr = pet_lines;
    else if (pet_lines->nup == 1 && vo->lines.nup == 1 &&
             pet_lines->hp_up_1 > vo->lines.hp_up_1)
      ptr = pet_lines;
  } else if (d < 0) {
    // check 2 dn lines
    if (pet_lines->ndn == 2 && vo->lines.ndn == 1 &&
        pet_lines->hp_dn_2 < vo->lines.hp_dn_1)
      ptr = pet_lines;
    else if (pet_lines->ndn == 2 && vo->lines.ndn == 2 &&
             pet_lines->hp_dn_2 > vo->lines.hp_dn_2)
      ptr = pet_lines;
    else if (pet_lines->nup == 1 && vo->lines.ndn == 1 &&
             pet_lines->hp_dn_1 > vo->lines.hp_dn_1)
      ptr = pet_lines;
  }
  return ptr;
}

const dir_t
TJM::get_cur_trade_dir() const noexcept
{
  dir_t d = 0;
  if (tom.is_running())
    d = tom.get_dir();
  else if (mickey.is_running())
    d = mickey.get_dir();
  return d;
}

} // namespace Trade